
/**
 * 加密安全的随机数生成工具模块
 * 提供多种随机数生成函数，支持不同环境下的加密安全随机数获取
 */
import CryptoJS from 'crypto-js';
/**
 * 生成指定长度的加密安全随机字节数组
 * @param {number} length 需要生成的随机字节数，必须大于0
 * @returns {Uint8Array} 包含随机字节的Uint8Array对象
 * @throws {Error} 当长度参数无效时抛出错误
 * @example
 * // 生成10个随机字节
 * const bytes = getRandomBytes(10);
 * console.log('随机字节:', Array.from(bytes));
 */
export function getRandomBytes(length: number): Uint8Array {
    if (length <= 0) throw new Error('长度必须大于0');

    // 创建指定长度的字节数组
    const bytes = new Uint8Array(length);

    // 方法1: 尝试浏览器原生的加密安全随机数生成器
    const browserCrypto = window.crypto || (window as any).msCrypto;
    if (browserCrypto && typeof browserCrypto.getRandomValues === 'function') {
        browserCrypto.getRandomValues(bytes);
        return bytes;
    }

    // 方法2: 尝试Node.js环境的crypto模块
    try {
        // 尝试动态导入Node.js的crypto模块（在浏览器环境中会失败）
        if (typeof require === 'function') {
            try {
                const nodeCrypto = require('crypto');
                if (nodeCrypto && typeof nodeCrypto.randomBytes === 'function') {
                    const nodeBuffer = nodeCrypto.randomBytes(length);
                    for (let i = 0; i < length; i++) {
                        bytes[i] = nodeBuffer[i];
                    }
                    return bytes;
                }
            } catch (e) {
                // Node.js crypto模块不可用，继续尝试其他方法
            }
        }
    } catch (e) {
        // 忽略导入错误
    }

    // 方法3: 使用crypto-js作为备选方案
    if (CryptoJS && CryptoJS.lib && CryptoJS.lib.WordArray) {
        const seed = CryptoJS.lib.WordArray.random(length);
        for (let i = 0; i < length; i++) {
            bytes[i] = seed.words[i >>> 2] >>> (24 - (i % 4) * 8) & 0xff;
        }
        return bytes;
    }

    return bytes;
}

/**
 * 生成指定长度的随机字符串
 * 使用加密安全的随机数生成器确保字符串的随机性
 * @param {number} length 字符串长度，默认16个字符
 * @param {string} charset 字符集，默认为大小写字母和数字的组合
 * @returns {string} 随机生成的字符串
 * @throws {Error} 当长度小于等于0或字符集为空时抛出错误
 * @example
 * // 生成默认的16位随机字符串
 * const randomStr = chars();
 * console.log(randomStr); // 例如: 'x7YpZ9A2b3C4d5E6'
 * 
 * // 生成8位数字验证码
 * const code = chars(8, '0123456789');
 * console.log(code); // 例如: '57392846'
 * 
 * // 生成特殊字符密码
 * const password = chars(20, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()');
 * console.log(password); // 例如: 'Xy7!Qp@R5$T8#Z9'
 */
export function chars(
    length: number = 16,
    charset: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
): string {
    if (length <= 0) throw new Error('长度必须大于0');
    if (!charset || charset.length === 0) throw new Error('字符集不能为空');

    // 使用getRandomBytes函数生成加密安全的随机数
    const array = getRandomBytes(length);

    let result = '';
    for (let i = 0; i < length; i++) {
        // 取模运算确保索引在字符集范围内
        const index = array[i] % charset.length;
        result += charset.charAt(index);
    }

    return result;
}

/**
 * 生成符合RFC4122版本4规范的UUID
 * 使用加密安全的随机数确保唯一性和安全性
 * @returns {string} 符合RFC4122规范的UUID字符串，格式为xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
 * @example
 * // 生成新的UUID
 * const id = uuid();
 * console.log(id); // 例如: '1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d'
 * 
 * // 用作唯一标识符
 * const user = {
 *   id: uuid(),
 *   name: '用户名'
 * };
 */
export function uuid(): string {
    // 获取16字节的随机数据
    const bytes = getRandomBytes(16);

    // 设置版本号为4（随机生成的UUID）
    bytes[6] = (bytes[6] & 0x0f) | 0x40;
    // 设置变体为RFC4122指定的格式
    bytes[8] = (bytes[8] & 0x3f) | 0x80;

    // 将字节转换为十六进制字符串并添加连字符
    let uuid = '';
    for (let i = 0; i < 16; i++) {
        const hex = bytes[i].toString(16).padStart(2, '0');
        uuid += hex;

        // 在指定位置添加连字符
        if (i === 3 || i === 5 || i === 7 || i === 9) {
            uuid += '-';
        }
    }

    return uuid;
}